fix: cinema mode is no-op on mobile; section order matches normal mode

Mobile (<800px) never really needed a different cinema layout — the
normal watch-mode mobile rules already stack images, purchase,
description, and comments in a single column with full-viewport-width
media. Cinema was re-ordering those sections (putting purchase AFTER
description/comments) and creating an inconsistency between cinema
and normal modes on the same device.

Fix: gate every cinema layout rule on @media (min-width: 800px). Below
that the .cinema-mode.cinema-wide classes exist but match no layout
rules, and the page falls through to normal mobile watch-mode.

JS: isViewportWideEnoughForCinema() uses the same 800px boundary to
decide whether to relocate the hamburger+Edit taskbar into the
sidebar. A debounced resize listener re-runs applyCinemaMode() so
the layout flips cleanly when the viewport crosses the boundary.
This commit is contained in:
russell@unturf.com 2026-04-23 13:58:21 -04:00
parent ababe32a0a
commit 7fa9c15a03
2 changed files with 117 additions and 117 deletions

View file

@ -1722,131 +1722,115 @@ textarea.markup-editor-textarea {
display: contents;
}
/* Cinema mode base applies at every viewport size. Desktop
(>=960px) enhances it to the 2-column layout. Narrow viewports
stack everything in a single column so cinema doesn't collapse
into natural block flow (which caused the "wasted whitespace"
state between 800px and 960px when nothing owned the layout). */
section.two-column.cinema-mode.cinema-wide {
display: grid;
grid-template-columns: 1fr;
grid-template-areas:
"images"
"content"
"purchase";
gap: 16px;
max-width: 100%;
padding-left: 8px;
padding-right: 8px;
align-items: start;
}
section.two-column.cinema-mode.cinema-wide .watch-left {
display: contents;
}
section.two-column.cinema-mode.cinema-wide .cinema-content-stack {
display: grid;
grid-area: content;
grid-template-rows: auto auto;
gap: 16px;
align-content: start;
min-width: 0;
}
section.two-column.cinema-mode.cinema-wide .product-images { grid-area: images; }
section.two-column.cinema-mode.cinema-wide section.product-right { grid-area: purchase; align-self: start; }
section.two-column.cinema-mode.cinema-wide .watch-video-container {
max-height: 92vh;
}
/* Cinema video/cover fills horizontal space. Intentional override
of the CLAUDE.md media-sizing rule cinema wants edge-to-edge
even if viewport aspect ratio forces a little letterbox.
object-fit:contain keeps aspect ratio safe. */
section.two-column.cinema-mode.cinema-wide .product-main,
section.two-column.cinema-mode.cinema-wide .watch-video-container > video,
section.two-column.cinema-mode.cinema-wide .watch-audio-container > .product-main {
width: 100%;
height: auto;
max-width: 100%;
max-height: 92vh;
object-fit: contain;
display: block;
margin-left: auto;
margin-right: auto;
}
/* Cinema: the main media is already showing at full viewport width,
so the wrapping "click to open in new window" link is redundant
and just steals the click from scrolling and other interactions. */
section.two-column.cinema-mode.cinema-wide .product-images > a[target="_blank"] {
pointer-events: none;
cursor: default;
}
/* Cinema: task bar (hamburger + Edit) relocates into .product-right
above the well via JS. Stack its children vertically and make it
feel like part of the sidebar rather than a floating chrome strip. */
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-task-bar {
grid-template-columns: 1fr;
padding: 0;
margin-bottom: 8px;
grid-gap: 8px;
}
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-start-button,
section.two-column.cinema-mode.cinema-wide section.product-right section.call-to-action {
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
}
/* Uniform button shape in the cinema sidebar hamburger, Edit, and
Download all read as the same component: full column width, same
padding, same type, same line height. Override the mps-button-small
shrink on Edit so it matches its siblings instead of looking like
a leftover chip. */
section.two-column.cinema-mode.cinema-wide section.product-right a.mps-button,
section.two-column.cinema-mode.cinema-wide section.product-right button.mps-button {
display: block;
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 14px 16px;
margin-top: 0;
margin-bottom: 8px;
font-size: var(--text-sm, 14px);
line-height: 1.3;
white-space: normal;
text-align: center;
}
/* Separate the comment section from the description block above and
the sidebar controls below so it reads as its own area, not just
more lines of text glued to the toolbar. */
section.two-column.cinema-mode.cinema-wide .product-comments {
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid var(--border-color, #ccc);
}
/* Cinema enhancement: split content | purchase into 2 columns as soon
as the viewport has room for it (>=800px). The base cinema rules
handle the single-column stack for narrower panels. Moved below the
usual 960px desktop threshold because cinema's full-width video +
stacked columns don't need as much horizontal room as a normal
product page with side-by-side hero + sidebar. */
/* Cinema mode applies only at >=800px. Below that, mobile watch-mode
layout already gives you full-viewport-width media + stacked sections
(images, purchase, description, comments), so cinema would just
re-order things for no visual gain and break consistency with the
normal mode on the same device. Fox: "mobile really doesn't need
cinema mode" we respect that by making cinema a no-op on mobile. */
@media (min-width: 800px) {
section.two-column.cinema-mode.cinema-wide {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-areas:
"images images"
"content purchase";
gap: 24px;
max-width: 100%;
padding-left: 20px;
padding-right: 20px;
align-items: start;
}
section.two-column.cinema-mode.cinema-wide .watch-left {
display: contents;
}
section.two-column.cinema-mode.cinema-wide .cinema-content-stack {
display: grid;
grid-area: content;
grid-template-rows: auto auto;
gap: 16px;
align-content: start;
min-width: 0;
}
section.two-column.cinema-mode.cinema-wide .product-images { grid-area: images; }
section.two-column.cinema-mode.cinema-wide section.product-right { grid-area: purchase; align-self: start; }
section.two-column.cinema-mode.cinema-wide .watch-video-container {
max-height: 92vh;
}
/* Cinema video/cover fills horizontal space. Intentional override
of the CLAUDE.md media-sizing rule cinema wants edge-to-edge
even if viewport aspect ratio forces a little letterbox.
object-fit:contain keeps aspect ratio safe. */
section.two-column.cinema-mode.cinema-wide .product-main,
section.two-column.cinema-mode.cinema-wide .watch-video-container > video,
section.two-column.cinema-mode.cinema-wide .watch-audio-container > .product-main {
width: 100%;
height: auto;
max-width: 100%;
max-height: 92vh;
object-fit: contain;
display: block;
margin-left: auto;
margin-right: auto;
}
/* Cinema: the main media is already showing at full viewport width,
so the wrapping "click to open in new window" link is redundant
and just steals the click from scrolling and other interactions. */
section.two-column.cinema-mode.cinema-wide .product-images > a[target="_blank"] {
pointer-events: none;
cursor: default;
}
/* Cinema: task bar (hamburger + Edit) relocates into .product-right
above the well via JS. Stack its children vertically and make it
feel like part of the sidebar rather than a floating chrome strip. */
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-task-bar {
grid-template-columns: 1fr;
padding: 0;
margin-bottom: 8px;
grid-gap: 8px;
}
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-start-button,
section.two-column.cinema-mode.cinema-wide section.product-right section.call-to-action {
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
}
/* Uniform button shape in the cinema sidebar hamburger, Edit, and
Download all read as the same component: full column width, same
padding, same type, same line height. Override the mps-button-small
shrink on Edit so it matches its siblings instead of looking like
a leftover chip. */
section.two-column.cinema-mode.cinema-wide section.product-right a.mps-button,
section.two-column.cinema-mode.cinema-wide section.product-right button.mps-button {
display: block;
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 14px 16px;
margin-top: 0;
margin-bottom: 8px;
font-size: var(--text-sm, 14px);
line-height: 1.3;
white-space: normal;
text-align: center;
}
/* Separate the comment section from the description block above and
the sidebar controls below so it reads as its own area, not just
more lines of text glued to the toolbar. */
section.two-column.cinema-mode.cinema-wide .product-comments {
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid var(--border-color, #ccc);
}
}

View file

@ -231,6 +231,14 @@
}
}
// Cinema layout only kicks in at >=800px — below that, mobile watch
// mode is already the right shape. Keep CSS + JS aligned on that
// boundary so the taskbar doesn't relocate on a phone.
var CINEMA_MIN_WIDTH = 800;
function isViewportWideEnoughForCinema() {
return window.innerWidth >= CINEMA_MIN_WIDTH;
}
function applyCinemaMode() {
var section = document.querySelector('section.two-column');
if (!section) return;
@ -239,7 +247,7 @@
var taskbar = document.querySelector('section.windows-95-task-bar');
var productRight = document.querySelector('section.product-right');
var wide = cinemaMode && isMediaWide();
var wide = cinemaMode && isMediaWide() && isViewportWideEnoughForCinema();
section.classList.toggle('cinema-mode', cinemaMode);
section.classList.toggle('cinema-wide', wide);
@ -259,6 +267,14 @@
}
applyCinemaMode();
// Re-evaluate when the viewport crosses the cinema breakpoint so
// rotation or browser resize flips the layout cleanly.
var _cinemaResizeTimer = null;
window.addEventListener('resize', function() {
if (_cinemaResizeTimer) clearTimeout(_cinemaResizeTimer);
_cinemaResizeTimer = setTimeout(applyCinemaMode, 120);
});
// Media type filter preferences (all on by default)
var FILTER_TYPES = ['video', 'audio', 'image', 'document', 'other'];
var FILTER_LABELS = {video: 'Video', audio: 'Audio', image: 'Image', document: 'Docs', other: 'Other'};