Compare commits

...

3 Commits

Author SHA1 Message Date
Disco DeDisco
0bcc7567bb XL landscape polish: btn-primary sizing, tray from right, footer bg, layout fixes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- .btn-xl removed; .btn-primary absorbs 4rem sizing (same as PICK SIGS/PICK ROLES)
- Landscape navbar .btn-primary: 3rem → 4rem to match base; XL stays 4rem (consistent)
- _button-pad.scss XL: base .btn ×1.2 (2.4rem); .btn-xl block deleted
- _tray.scss XL (≥1800px): portrait-style tray (slides from right, z-95)
- tray.js: _isLandscape() returns false at ≥1800px; portrait code paths run throughout
- Footer sidebar: background-color added so opaque footer masks tray sliding behind it
- Copyright .footer-container: bottom → top in landscape sidebar
- #id_room_menu: right: 2.5rem override in _room.scss XL block (cascade fix)
- navbar-text XL: 0.65rem × 1.2 = 0.78rem
- All landscape media queries: max-width: 1440px cutoff removed (already done prior)
- btn-xl class stripped from all 5 templates; test_navbar.py assertion updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 03:02:37 -04:00
Disco DeDisco
6654785f25 XL landscape breakpoint (≥1800px): double sidebar widths + scale content
- _base.scss: new @media (orientation:landscape) and (min-width:1800px) block —
  sidebars 4rem→8rem; navbar btn 3rem→5rem; brand h1 1.2rem→2.4rem; navbar-text
  0.65rem→1.3rem; footer icons 1.75rem→3rem; nav gap 3rem→4rem; footer-container
  0.55rem→0.85rem; container margins 4rem→8rem; h2 portrait-style (2rem, centred)
- _applets.scss: gear btn right 0.5rem→2.5rem; menus right 0.5rem→2rem at ≥1800px
- _game-kit.scss: kit btn right 0.5rem→2.5rem at ≥1800px
- _room.scss: sig-overlay padding-left 4rem→8rem at ≥1800px
- _tray.scss: tray wrap left/right 4rem→8rem at ≥1800px
- room.js: sizeSigModal right inset 64px→128px at ≥1800px viewport width

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 01:41:18 -04:00
Disco DeDisco
99a69202b9 landscape layout: remove max-width cutoff; sig-select stage/grid polish
- All landscape @media queries: drop and (max-width: 1440px) — sidebar layout
  now activates for all landscape orientations regardless of viewport width
- _base.scss landscape container: add max-width:none to override the
  @media(min-width:1200px) rule and fill the full space between sidebars
- sig-select sig-deck-grid: landscape now 9×2 @ 3rem cards; 18×1 at ≥1100px
  (bumped from 992px to avoid last-card clip); card text scales with --sig-card-w
- sig-stat-block: flex:1→flex:0 0 auto with width:--sig-card-w so it matches
  preview card dimensions instead of stretching across the full stage
- room.js sizeSigModal: landscape card width clamped to [90px, 160px]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 01:30:31 -04:00
16 changed files with 244 additions and 98 deletions

View File

@@ -61,11 +61,13 @@
} }
}); });
// Landscape: right clears gear/kit buttons (~4rem); bottom is fixed 60px for // Landscape: right clears gear/kit buttons; bottom is fixed 60px for the
// the kit-bag handle strip — tray is ignored so the stage has room to breathe. // kit-bag handle strip — tray is ignored so the stage has room to breathe.
// At ≥1800px the right sidebar doubles to 8rem so clear 128px.
if (isLandscape) { if (isLandscape) {
rightInset = Math.max(rightInset, 64); // 4rem var xlBreak = vw >= 1800;
bottomInset = 60; // kit-bag handle rightInset = Math.max(rightInset, xlBreak ? 128 : 64);
bottomInset = 60;
} }
overlay.style.paddingRight = rightInset + 'px'; overlay.style.paddingRight = rightInset + 'px';
@@ -78,7 +80,11 @@
var sw = stageEl.offsetWidth - 24; // subtract padding (0.75rem × 2) var sw = stageEl.offsetWidth - 24; // subtract padding (0.75rem × 2)
var sh = stageEl.offsetHeight - 24; var sh = stageEl.offsetHeight - 24;
if (sw > 0 && sh > 0) { if (sw > 0 && sh > 0) {
var cardW = Math.min(sw * 0.4, sh * 0.8 * 5 / 8); // Clamp between 90px (never tiny in landscape) and 160px (never
// dominant on very wide/tall viewports). In portrait, skip the
// floor so small modals still scale down naturally.
var cardW = Math.min(sw * 0.4, sh * 0.8 * 5 / 8, 160);
if (isLandscape) { cardW = Math.max(cardW, 90); }
overlay.style.setProperty('--sig-card-w', cardW + 'px'); overlay.style.setProperty('--sig-card-w', cardW + 'px');
} }
} }

View File

@@ -40,6 +40,9 @@ var Tray = (function () {
function _isLandscape() { function _isLandscape() {
if (_landscapeOverride !== null) return _landscapeOverride; if (_landscapeOverride !== null) return _landscapeOverride;
// ≥1800px uses portrait-style tray (slides from right) to match the
// doubled sidebar widths and XL tray CSS reset.
if (window.innerWidth >= 1800) return false;
return window.innerWidth > window.innerHeight; return window.innerWidth > window.innerHeight;
} }
@@ -94,12 +97,10 @@ var Tray = (function () {
// Closed: tray hidden above viewport, handle visible at y=0. // Closed: tray hidden above viewport, handle visible at y=0.
_maxTop = -(gearBtnTop - handleH); _maxTop = -(gearBtnTop - handleH);
} else { } else {
// Portrait: slide on X axis. // Portrait (and XL landscape, which uses portrait-style tray):
// Wrap width is pinned to viewportW (JS) so its right edge only // Wrap width = viewportW so the closed right edge reaches the viewport boundary.
// reaches the viewport boundary when left = 0 (fully open). // The footer sidebar (z-100) is above the wrap (z-95) and has a solid background,
// This mirrors landscape: the open edge appears only at the last moment. // so the handle parks behind it and slides out from under it when opened.
// Open: left = 0 → wrap right = viewportW exactly.
// Closed: left = viewportW - handleW → tray fully off-screen right.
var handleW = _btn.offsetWidth || 48; var handleW = _btn.offsetWidth || 48;
if (_wrap) _wrap.style.width = window.innerWidth + 'px'; if (_wrap) _wrap.style.width = window.innerWidth + 'px';
_minLeft = 0; _minLeft = 0;
@@ -313,7 +314,7 @@ var Tray = (function () {
} }
} else { } else {
if (_tray) _tray.style.display = 'none'; if (_tray) _tray.style.display = 'none';
if (_wrap) { _wrap.style.top = ''; _wrap.style.height = ''; } if (_wrap) { _wrap.style.top = ''; _wrap.style.height = ''; _wrap.style.width = ''; }
_computeBounds(); _computeBounds();
_applyVerticalBounds(); _applyVerticalBounds();
_computeCellSize(); _computeCellSize();
@@ -342,8 +343,8 @@ var Tray = (function () {
if (_wrap) _wrap.style.top = _maxTop + 'px'; if (_wrap) _wrap.style.top = _maxTop + 'px';
_computeCellSize(); _computeCellSize();
} else { } else {
// Clear landscape's inline top so portrait CSS applies. // Clear landscape's inline top/height/width so portrait CSS applies.
if (_wrap) _wrap.style.top = ''; if (_wrap) { _wrap.style.top = ''; _wrap.style.width = ''; }
_applyVerticalBounds(); _applyVerticalBounds();
_computeCellSize(); // wrap has correct height after _applyVerticalBounds _computeCellSize(); // wrap has correct height after _applyVerticalBounds
_computeBounds(); _computeBounds();

View File

@@ -113,7 +113,7 @@ class NavbarByeTest(FunctionalTest):
class NavbarContGameTest(FunctionalTest): class NavbarContGameTest(FunctionalTest):
""" """
When the authenticated user has at least one room with a game event the When the authenticated user has at least one room with a game event the
CONT GAME btn-primary btn-xl appears in the navbar and navigates to that CONT GAME btn-primary appears in the navbar and navigates to that
room on confirmation. Its tooltip must also appear below the button. room on confirmation. Its tooltip must also appear below the button.
""" """
@@ -139,7 +139,6 @@ class NavbarContGameTest(FunctionalTest):
) )
btn = self.browser.find_element(By.ID, "id_cont_game") btn = self.browser.find_element(By.ID, "id_cont_game")
self.assertIn("btn-primary", btn.get_attribute("class")) self.assertIn("btn-primary", btn.get_attribute("class"))
self.assertIn("btn-xl", btn.get_attribute("class"))
# ------------------------------------------------------------------ # # ------------------------------------------------------------------ #
# T6 — CONT GAME tooltip appears below btn # # T6 — CONT GAME tooltip appears below btn #

View File

@@ -110,7 +110,8 @@
} }
// In landscape: shift gear btn and applet menus left of the footer right sidebar // In landscape: shift gear btn and applet menus left of the footer right sidebar
@media (orientation: landscape) and (max-width: 1440px) { // XL override below doubles sidebar to 8rem — centre items in the wider column.
@media (orientation: landscape) {
$sidebar-w: 4rem; $sidebar-w: 4rem;
.gameboard-page, .gameboard-page,
@@ -119,7 +120,7 @@
.room-page, .room-page,
.billboard-page { .billboard-page {
> .gear-btn { > .gear-btn {
right: 0.5rem; right: 1rem;
bottom: 3.95rem; // same gap above kit btn as portrait; no page-specific overrides needed bottom: 3.95rem; // same gap above kit btn as portrait; no page-specific overrides needed
top: auto; top: auto;
} }
@@ -131,12 +132,30 @@
#id_wallet_applet_menu, #id_wallet_applet_menu,
#id_room_menu, #id_room_menu,
#id_billboard_applet_menu { #id_billboard_applet_menu {
right: 0.5rem; right: 1rem;
bottom: 6.6rem; bottom: 6.6rem;
top: auto; top: auto;
} }
} }
@media (orientation: landscape) and (min-width: 1800px) {
// Centre gear btn and menus in the doubled 8rem sidebar (was 0.5rem from right edge)
.gameboard-page,
.dashboard-page,
.wallet-page,
.room-page,
.billboard-page {
> .gear-btn { right: 2.5rem; }
}
#id_dash_applet_menu,
#id_game_applet_menu,
#id_game_kit_menu,
#id_wallet_applet_menu,
#id_room_menu,
#id_billboard_applet_menu { right: 2.5rem; }
}
// ── Applet box visual shell (reusable outside the grid) ──── // ── Applet box visual shell (reusable outside the grid) ────
%applet-box { %applet-box {
border: border:

View File

@@ -35,6 +35,7 @@ body {
} }
} }
.container-fluid { .container-fluid {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -192,8 +193,8 @@ body {
} }
} }
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
$sidebar-w: 4rem; $sidebar-w: 5rem;
// ── Sidebar layout: navbar ← left, footer → right ──────────────────────────── // ── Sidebar layout: navbar ← left, footer → right ────────────────────────────
body { body {
@@ -265,11 +266,10 @@ body {
} }
.btn-primary { .btn-primary {
width: 3rem; width: 4rem;
height: 3rem; height: 4rem;
font-size: 0.75rem; font-size: 0.875rem;
border-width: 0.125rem; border-width: 0.21rem;
// margin-left: 0.75rem;
} }
// Login form: offset from fixed sidebars in landscape // Login form: offset from fixed sidebars in landscape
@@ -288,10 +288,13 @@ body {
} }
} }
// Container: fill center, compensate for fixed sidebars on both sides // Container: fill center, compensate for fixed sidebars on both sides.
// max-width: none overrides the @media (min-width: 1200px) rule above so the
// container fills all available space between the two sidebars on wide screens.
body .container { body .container {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
max-width: none;
margin-left: $sidebar-w; margin-left: $sidebar-w;
margin-right: $sidebar-w; margin-right: $sidebar-w;
padding: 0 0.5rem; padding: 0 0.5rem;
@@ -324,6 +327,7 @@ body {
align-items: center; align-items: center;
border-top: none; border-top: none;
border-left: 0.1rem solid rgba(var(--secUser), 0.3); border-left: 0.1rem solid rgba(var(--secUser), 0.3);
background-color: rgba(var(--priUser), 1); // opaque: masks tray sliding behind it
padding: 1rem 0; padding: 1rem 0;
gap: 0; gap: 0;
z-index: 100; z-index: 100;
@@ -344,17 +348,64 @@ body {
.footer-container { .footer-container {
position: absolute; position: absolute;
bottom: 0.75rem; top: 0.75rem;
text-align: center; text-align: center;
font-size: 0.55rem; font-size: 1rem;
line-height: 1.4; line-height: 1.4;
color: rgba(var(--secUser), 0.5); color: rgba(var(--secUser), 1);
br { display: block; } br { display: block; }
} }
} }
} }
// ── XL landscape (≥1800px): double sidebar widths and scale content ────────────
@media (orientation: landscape) and (min-width: 1800px) {
$sidebar-xl: 8rem;
body .container .navbar {
width: $sidebar-xl;
.container-fluid {
gap: 2rem;
padding: 0 0.5rem;
}
.navbar-brand h1 { font-size: 2.4rem; }
.navbar-text { font-size: 0.78rem; } // 0.65rem × 1.2
.btn-primary { width: 4rem; height: 4rem; font-size: 0.875rem; }
.input-group {
left: $sidebar-xl;
right: $sidebar-xl;
}
}
body .container {
margin-left: $sidebar-xl;
margin-right: $sidebar-xl;
}
// h2 page title: portrait-style — centred and full-size on a wide canvas
body .container .row .col-lg-6 h2 {
font-size: 4rem;
letter-spacing: 1em;
text-align: center;
text-align-last: center;
}
body #id_footer {
width: $sidebar-xl;
#id_footer_nav {
gap: 8rem;
a { font-size: 3rem; }
}
.footer-container { font-size: 0.85rem; }
}
}
@media (orientation: portrait) and (max-width: 500px) { @media (orientation: portrait) and (max-width: 500px) {
body .container { body .container {
.navbar { .navbar {
@@ -363,13 +414,6 @@ body {
.navbar-brand h1 { .navbar-brand h1 {
font-size: 1.2rem; font-size: 1.2rem;
} }
.btn-primary {
width: 3rem;
height: 3rem;
font-size: 0.75rem;
border-width: 0.125rem;
}
} }
.row .col-lg-6 h2 { .row .col-lg-6 h2 {
@@ -436,8 +480,8 @@ body {
br { display: none; } br { display: none; }
small { small {
font-size: 0.7rem; font-size: 0.75rem;
opacity: 0.6; opacity: 1;
} }
} }
} }

View File

@@ -25,6 +25,10 @@
} }
&.btn-primary { &.btn-primary {
width: 4rem;
height: 4rem;
font-size: 0.875rem;
border-width: 0.21rem;
color: rgba(var(--quaUser), 1); color: rgba(var(--quaUser), 1);
border-color: rgba(var(--quaUser), 1); border-color: rgba(var(--quaUser), 1);
background-color: rgba(var(--quiUser), 1); background-color: rgba(var(--quiUser), 1);
@@ -34,37 +38,6 @@
0.25rem 0.25rem 0.25rem rgba(var(--quiUser), 0.12) 0.25rem 0.25rem 0.25rem rgba(var(--quiUser), 0.12)
; ;
&:hover {
text-shadow:
0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25),
0 0 1rem rgba(var(--quaUser), 1)
;
box-shadow:
0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--quaUser), 0.12)
;
}
&:active {
border: 0.18rem solid rgba(var(--quaUser), 1);
text-shadow:
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25),
0 0 0.12rem rgba(var(--quaUser), 1)
;
box-shadow:
-0.1rem -0.1rem 0.12rem rgba(var(--quiUser), 0.25),
-0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--quaUser), 0.12)
;
}
}
&.btn-xl {
width: 4rem;
height: 4rem;
font-size: 0.875rem;
border-width: 0.21rem;
&:hover { &:hover {
text-shadow: text-shadow:
0.2rem 0.2rem 0.2rem rgba(0, 0, 0, 0.25), 0.2rem 0.2rem 0.2rem rgba(0, 0, 0, 0.25),
@@ -72,7 +45,7 @@
; ;
box-shadow: box-shadow:
0.24rem 0.24rem 0.5rem rgba(0, 0, 0, 0.25), 0.24rem 0.24rem 0.5rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--quaUser), 22) 0 0 0.5rem rgba(var(--quaUser), 0.22)
; ;
} }
@@ -300,6 +273,12 @@
} }
} }
@media (orientation: landscape) and (min-width: 1800px) {
width: 2.4rem; // 2rem × 1.2
height: 2.4rem;
font-size: 0.75rem; // 0.63rem × 1.2
}
&.btn-disabled { &.btn-disabled {
cursor: default !important; cursor: default !important;
font-size: 1.2rem; font-size: 1.2rem;

View File

@@ -149,7 +149,7 @@ body.page-dashboard {
} }
} }
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
// Reset the 666px min-width so #id_dash_content shrinks to fit within the // Reset the 666px min-width so #id_dash_content shrinks to fit within the
// sidebar-bounded container rather than overflowing into the footer sidebar. // sidebar-bounded container rather than overflowing into the footer sidebar.
#id_dash_content { #id_dash_content {

View File

@@ -3,12 +3,16 @@
bottom: 0.5rem; bottom: 0.5rem;
right: 0.5rem; right: 0.5rem;
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
right: 0.5rem; right: 1rem;
bottom: 0.5rem; bottom: 0.5rem;
top: auto; top: auto;
} }
@media (orientation: landscape) and (min-width: 1800px) {
right: 2.5rem; // centre in doubled 8rem sidebar
}
z-index: 318; z-index: 318;
font-size: 1.75rem; font-size: 1.75rem;
cursor: pointer; cursor: pointer;
@@ -45,7 +49,7 @@
z-index: 316; z-index: 316;
overflow: hidden; overflow: hidden;
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
$sidebar-w: 4rem; $sidebar-w: 4rem;
// left: $sidebar-w; // left: $sidebar-w;
right: $sidebar-w; right: $sidebar-w;

View File

@@ -46,7 +46,7 @@ body.page-gameboard {
} }
} }
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
// Restore clip in landscape — overrides the >738px overflow:visible above, // Restore clip in landscape — overrides the >738px overflow:visible above,
// preventing the gameboard applets from bleeding into the footer sidebar. // preventing the gameboard applets from bleeding into the footer sidebar.
body.page-gameboard .container { body.page-gameboard .container {

View File

@@ -800,7 +800,7 @@ $card-h: 60px;
} }
// Landscape mobile — aggressively scale down to fit short viewport // Landscape mobile — aggressively scale down to fit short viewport
@media (orientation: landscape) and (max-width: 1440px) { @media (orientation: landscape) {
// Sink navbar below gate/role-select overlays when a modal is open. // Sink navbar below gate/role-select overlays when a modal is open.
// Landscape navbar z-index is 100 (_base.scss); gate-backdrop/overlay are // Landscape navbar z-index is 100 (_base.scss); gate-backdrop/overlay are
// 100/120 — same level causes paint-order ties so we drop it to 50. // 100/120 — same level causes paint-order ties so we drop it to 50.
@@ -909,6 +909,7 @@ html:has(.sig-backdrop) {
// game-kit sets .fan-card-corner { position: absolute; top/left offsets } // game-kit sets .fan-card-corner { position: absolute; top/left offsets }
// so these just need display/font overrides; the corners land at the card edges. // so these just need display/font overrides; the corners land at the card edges.
// All font-sizes scale with --sig-card-w (ratio = original-rem × 16 / 120).
.fan-card-corner--tl { .fan-card-corner--tl {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -916,8 +917,8 @@ html:has(.sig-backdrop) {
line-height: 1.1; line-height: 1.1;
gap: 0.1rem; gap: 0.1rem;
.fan-corner-rank { font-size: 1rem; font-weight: 700; } .fan-corner-rank { font-size: calc(var(--sig-card-w, 120px) * 0.133); font-weight: 700; }
i { font-size: 0.75rem; } i { font-size: calc(var(--sig-card-w, 120px) * 0.1); }
} }
.fan-card-corner--br { .fan-card-corner--br {
@@ -927,8 +928,8 @@ html:has(.sig-backdrop) {
line-height: 1.1; line-height: 1.1;
gap: 0.1rem; gap: 0.1rem;
.fan-corner-rank { font-size: 0.9rem; font-weight: 700; } .fan-corner-rank { font-size: calc(var(--sig-card-w, 120px) * 0.12); font-weight: 700; }
i { font-size: 0.75rem; } i { font-size: calc(var(--sig-card-w, 120px) * 0.1); }
} }
.fan-card-face { .fan-card-face {
@@ -941,20 +942,22 @@ html:has(.sig-backdrop) {
padding: 0.25rem 0.15rem; padding: 0.25rem 0.15rem;
gap: 0.2rem; gap: 0.2rem;
.fan-card-name-group { font-size: 0.55rem; opacity: 0.6; } .fan-card-name-group { font-size: calc(var(--sig-card-w, 120px) * 0.073); opacity: 0.6; }
.fan-card-name { font-size: 0.7rem; font-weight: 600; } .fan-card-name { font-size: calc(var(--sig-card-w, 120px) * 0.093); font-weight: 600; }
.fan-card-arcana { font-size: 0.5rem; text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.5; } .fan-card-arcana { font-size: calc(var(--sig-card-w, 120px) * 0.067); text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.5; }
.fan-card-correspondence{ font-size: 0.5rem; opacity: 0.5; } .fan-card-correspondence{ font-size: calc(var(--sig-card-w, 120px) * 0.067); opacity: 0.5; }
} }
} }
// Stat block — same height as the preview card; fills remaining stage width. // Stat block — same dimensions as the preview card (width × 5:8 aspect).
// Height derived from the JS-computed --sig-card-w via aspect ratio 5:8. // flex: 0 0 auto so it doesn't stretch to fill the stage; the rest of the
// stage row is simply empty, giving the card room to breathe.
.sig-stat-block { .sig-stat-block {
flex: 1; flex: 0 0 auto;
width: var(--sig-card-w, 120px);
height: calc(var(--sig-card-w, 120px) * 8 / 5); height: calc(var(--sig-card-w, 120px) * 8 / 5);
align-self: flex-end; align-self: flex-end;
background: rgba(var(--priUser), 0.25); background: rgba(var(--priUser), 0.5);
border-radius: 0.4rem; border-radius: 0.4rem;
border: 0.1rem solid rgba(var(--terUser), 0.15); border: 0.1rem solid rgba(var(--terUser), 0.15);
display: none; display: none;
@@ -1074,17 +1077,34 @@ html:has(.sig-backdrop) {
} }
// ─── Sig select: landscape overrides ───────────────────────────────────────── // ─── Sig select: landscape overrides ─────────────────────────────────────────
// Wider viewport → 2 rows of 9 cards; modal fills full available width. // Landscape base: 9×2 grid of 3rem cards. At ≥992px (wide enough for 18 cards
// at 3rem + 4rem left + ~4rem right): collapse to a single 18×1 row so the
// stage preview gets maximum vertical real-estate.
// padding-left clears the fixed left navbar (JS sets right/bottom but not left). // padding-left clears the fixed left navbar (JS sets right/bottom but not left).
// Grid margins reset to 0 — overlay padding handles all edge clearance in landscape. // Grid margins reset to 0 — overlay padding handles all edge clearance.
@media (orientation: landscape) { @media (orientation: landscape) {
.sig-overlay { padding-left: 4rem; } .sig-overlay { padding-left: 4rem; }
.sig-modal { max-width: none; } .sig-modal { max-width: none; }
.sig-deck-grid { .sig-deck-grid {
grid-template-columns: repeat(9, minmax(0, 90px)); grid-template-columns: repeat(9, 3rem);
margin: 0; margin: 0;
} }
} }
@media (orientation: landscape) and (min-width: 1100px) {
.sig-deck-grid {
grid-template-columns: repeat(18, 3rem);
}
}
@media (orientation: landscape) and (min-width: 1800px) {
// Sig overlay: clear doubled navbar sidebar (8rem instead of 4rem)
.sig-overlay { padding-left: 8rem; }
// Room menu: base right: 0.5rem (same-specificity ID rule) overrides _applets.scss
// XL block because _room.scss is imported later. Re-declare here to win the cascade.
#id_room_menu { right: 2.5rem; }
}
// ─── Seat tray — see _tray.scss ───────────────────────────────────────────── // ─── Seat tray — see _tray.scss ─────────────────────────────────────────────

View File

@@ -328,3 +328,77 @@ $handle-r: 1rem;
80% { transform: translateY(-3px); } 80% { transform: translateY(-3px); }
} }
} }
// ── XL landscape (≥1800px): portrait-style tray — slides in from right ─────
// Overrides all landscape rules above. JS also returns false from _isLandscape()
// at this width so portrait code paths run throughout.
@media (orientation: landscape) and (min-width: 1800px) {
#id_tray_wrap {
flex-direction: row;
top: 0;
bottom: 0;
left: auto; // JS controls left; width set to innerWidth so wrap fills viewport
right: auto;
height: auto;
width: auto;
z-index: 95; // below footer/nav sidebars (z-100) — opaque footer masks the tray
transition: left 0.35s cubic-bezier(0.4, 0, 0.2, 1);
&.wobble { animation: tray-wobble 0.45s ease; }
&.snap { animation: tray-snap 0.30s ease; }
}
#id_tray_handle {
width: $handle-exposed; // 48px portrait strip
height: auto;
}
#id_tray_grip {
top: 50%;
bottom: auto;
left: calc(#{$handle-exposed} / 2 - 0.125rem);
transform: translateY(-50%);
width: $handle-rect-w; // 10000px extends leftward
height: $handle-rect-h; // 72px
}
#id_tray {
border-left: 2.5rem solid rgba(var(--quaUser), 1);
border-top: 2.5rem solid rgba(var(--quaUser), 1);
border-bottom: 2.5rem solid rgba(var(--quaUser), 1);
border-right: none;
margin-left: 0.5rem;
margin-bottom: 0;
width: auto;
max-width: none;
align-self: auto;
flex: 1;
height: auto;
overflow: hidden;
box-shadow:
-0.25rem 0 0.5rem rgba(0, 0, 0, 0.55),
inset 0 0 0 0.3rem rgba(var(--quiUser), 0.45),
inset 0.6rem 0 1.5rem -0.5rem rgba(0, 0, 0, 1),
inset 0.6rem 0 1.5rem -0.5rem rgba(var(--quiUser), 0.5),
inset 0 0.6rem 1.5rem -0.5rem rgba(0, 0, 0, 1),
inset 0 0.6rem 1.5rem -0.5rem rgba(var(--quiUser), 0.5),
inset 0 -0.6rem 1.5rem -0.5rem rgba(0, 0, 0, 1),
inset 0 -0.6rem 1.5rem -0.5rem rgba(var(--quiUser), 0.5)
;
}
#id_tray_grid {
grid-template-columns: none;
grid-template-rows: repeat(8, var(--tray-cell-size, 48px));
grid-auto-flow: column;
grid-auto-columns: var(--tray-cell-size, 48px);
grid-auto-rows: auto;
position: static;
}
.tray-cell {
border-top: none;
border-right: 2px dotted rgba(var(--priUser), 0.35);
border-bottom: 2px dotted rgba(var(--priUser), 0.35);
}
}

View File

@@ -41,7 +41,7 @@
</div> </div>
{% endif %} {% endif %}
<button type="submit" class="btn btn-primary btn-xl">Share</button> <button type="submit" class="btn btn-primary">Share</button>
</form> </form>
<small>Note shared with: <small>Note shared with:
{% for user in note.shared_with.all %} {% for user in note.shared_with.all %}

View File

@@ -53,7 +53,7 @@
{% if room.gate_status == 'OPEN' %} {% if room.gate_status == 'OPEN' %}
<form method="POST" action="{% url 'epic:pick_roles' room.id %}" style="display:contents"> <form method="POST" action="{% url 'epic:pick_roles' room.id %}" style="display:contents">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="launch-game-btn btn btn-primary btn-xl">PICK ROLES</button> <button type="submit" class="launch-game-btn btn btn-primary">PICK ROLES</button>
</form> </form>
{% endif %} {% endif %}
</div> </div>

View File

@@ -8,7 +8,7 @@
<form method="POST" action="{% url 'epic:confirm_token' room.id %}"> <form method="POST" action="{% url 'epic:confirm_token' room.id %}">
{% csrf_token %} {% csrf_token %}
{% if is_last_slot %} {% if is_last_slot %}
<button type="submit" class="btn btn-primary btn-xl">PICK ROLES</button> <button type="submit" class="btn btn-primary">PICK ROLES</button>
{% else %} {% else %}
<button type="submit" class="btn btn-confirm">OK</button> <button type="submit" class="btn btn-confirm">OK</button>
{% endif %} {% endif %}

View File

@@ -14,7 +14,7 @@
<div id="id_pick_sigs_wrap"{% if starter_roles|length < 6 %} style="display:none"{% endif %}> <div id="id_pick_sigs_wrap"{% if starter_roles|length < 6 %} style="display:none"{% endif %}>
<form method="POST" action="{% url 'epic:pick_sigs' room.id %}"> <form method="POST" action="{% url 'epic:pick_sigs' room.id %}">
{% csrf_token %} {% csrf_token %}
<button id="id_pick_sigs_btn" type="submit" class="btn btn-primary btn-xl">PICK<br>SIGS</button> <button id="id_pick_sigs_btn" type="submit" class="btn btn-primary">PICK<br>SIGS</button>
</form> </form>
</div> </div>
{% endif %} {% endif %}

View File

@@ -24,7 +24,7 @@
{% if navbar_recent_room_url %} {% if navbar_recent_room_url %}
<button <button
id="id_cont_game" id="id_cont_game"
class="btn btn-primary btn-xl" class="btn btn-primary"
type="button" type="button"
data-confirm="Continue game?" data-confirm="Continue game?"
data-href="{{ navbar_recent_room_url }}" data-href="{{ navbar_recent_room_url }}"