Compare commits

...

2 Commits

Author SHA1 Message Date
Disco DeDisco
c4279c5515 room title reel: fix the landscape view-to-view + hex⇄views motion (vertical-rl axis)
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful
- In landscape the wordmark is `writing-mode: vertical-rl` + `rotate(180deg)`. The rotation runs every reel child's translate in the rotated frame (inverting motion vs portrait), and the vertical-rl forces the flex MAIN axis onto the vertical, so the five view-word cells stack vertically.
- Vertical reel (hex⇄views): negate the translateY so ROOM exits UP + the view reel rises from BELOW (was dropping ROOM below the rising view).
- Lateral reel (view-to-view): the cells stack vertically, so the portrait `translateX` slid that stack sideways off the slot — only one word rendered (desktop showed PULSE, mobile ATLAS; `row`/`column`/`order`/`row-reverse` all collapse). Traverse with `translateY` instead: the words now slide up-down ALONG the rotated wordmark and each view lands its own word, consistently across desktop + mobile. (True left-right needs a track writing-mode override + reopens the rotate inversion — deferred; up-down is the working result.)
- `overflow: hidden` on the view reel clips it to its one-slot box so the neighbouring cell can't bleed over ROOM (the lateral reel now shares the vertical axis with the hex⇄views reel).
- Pure SCSS, verified visually across desktop + mobile landscape; portrait untouched (all rules inside the landscape media query).

[[feedback-vertical-rl-flex-axis]] [[project-room-game-views-carousel]]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 01:13:09 -04:00
Disco DeDisco
fc49ca2c74 game post: New Post applet treatment — --duoUser felt, green-tinted title strip + input-pill .post-line rows
- The reelhouse POST card now takes the billboard New Post applet's look: a --duoUser green felt bg with the rotated room-name `> h2` given the SAME green-tinted strip — three translucent 0,0,0/0.125 layers over the felt, NO opaque base, so the felt shows through (matches #id_applet_new_post, which lands there via a %applet-box > h2 specificity quirk; we do it on purpose).
- Each .post-line is restyled to LOOK LIKE the "Enter a post line" composer input below it (mirrors .form-control, _base.scss): a --priUser fill (0.8 alpha), a 0.1rem --secUser border at the same border-radius, full width, an up/down margin + content-driven (dynamic) height — so the thread reads as a stack of input-style pills on the felt. #id_post_table left/right padding zeroed so pills span the full card content width (= the composer row).
- OK button wrapped in .applet-btn-panel (--priUser fill + faint --terUser border) so the green .btn-confirm reads against the felt, mirroring the New Post composer.
- All scoped to .room-view--post — post.html (.post-page), the billboard New Post applet, and MY POSTS (.applet-list-entry) stay untouched (verified live: no .post-line bleed).
- Verified: GameViewsCarouselTest.test_post_view_is_room_thread_with_working_composer + test_atlas_aggregates_provenance_and_posts green (composer still works with the OK-panel wrap); billboard + GAME POST visually confirmed via Claudezilla.

[[feedback-scss-id-context-specificity-trap]] — %applet-box > h2's background-color inherits the applets-container ID via the @extend chain, out-specifying a plain #id_applet > h2 override, so an "opaque base" mask silently renders translucent (the felt bleeds through). New Post hit this by accident; GAME POST replicates it deliberately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 22:52:33 -04:00
3 changed files with 70 additions and 3 deletions

View File

@@ -586,6 +586,36 @@ body {
padding-inline: 7%; // top+bottom inset (vertical-rl) — supersedes the 0.4em start gap
}
// ── Reel motion in landscape: match portrait ─────────────────────────────
// The wordmark's `rotate(180deg)` (above) gives the bottom-to-top reading but
// ALSO runs every reel child's translate in the rotated frame, so all motion
// is inverted vs portrait. Target is portrait directions, so negate the
// translates here (they read correct AFTER the rotation) while the glyphs keep
// the parent's rotation. NB: translate values only — no extra transform on the
// words, so they stay rotated/readable.
//
// Vertical reel (hex⇄views): ROOM exits UP, the view reel rises from BELOW —
// as in portrait (was inverted: ROOM dropped below the view). Park the reel
// below (negated) + send ROOM up on `.is-scroll` (negated). The reel's
// in-slot `.is-scroll` translateY(0) is unchanged, so it's inherited as-is.
body .container .row .col-lg-6 h2 .gr-views-reel { transform: translateY(-100%); overflow: hidden; }
body .container .row .col-lg-6 h2.is-scroll .gr-word--base { transform: translateY(100%); }
//
// Lateral reel (view-to-view): in landscape the wordmark is `writing-mode:
// vertical-rl`, which forces the flex main axis onto the vertical, so the five
// cells stack vertically no matter the flex-direction (`row`/`column`/`order`/
// `row-reverse` all collapse to one cell under a horizontal translateX). So
// traverse the stack with `translateY` — the words slide up-down ALONG the
// rotated wordmark (the faithful rotation of portrait's lateral slide). The
// reel's overflow:hidden above keeps the neighbouring cell from bleeding over
// ROOM (this reel now shares the vertical axis with the hex⇄views reel).
body .container .row .col-lg-6 h2 .gr-views-track { transform: translateY(-100%); }
body .container .row .col-lg-6 h2[data-active-view="atlas"] .gr-views-track { transform: translateY(0); }
body .container .row .col-lg-6 h2[data-active-view="scroll"] .gr-views-track { transform: translateY(-100%); }
body .container .row .col-lg-6 h2[data-active-view="yarn"] .gr-views-track { transform: translateY(-200%); }
body .container .row .col-lg-6 h2[data-active-view="post"] .gr-views-track { transform: translateY(-300%); }
body .container .row .col-lg-6 h2[data-active-view="pulse"] .gr-views-track { transform: translateY(-400%); }
// Footer → fixed right sidebar (mirrors navbar approach — explicit right boundary)
// Use body #id_footer (specificity 0,1,0,1) to beat base #id_footer (0,1,0,0)
// which compiles later in the output and would otherwise override height: 100vh.

View File

@@ -178,10 +178,32 @@ html.sea-open #id_aperture_fill {
// _post_line.html). The post styling proper is .post-page-scoped, so the
// essentials are restated here for the carousel card.
.room-view--post {
// New Post applet treatment (mirrors #id_applet_new_post in _applets.scss):
// a --duoUser green-felt card. The rotated room-name `> h2` gets the SAME
// green-tinted strip as the billboard New Post title — the felt shows
// through (see the `> h2` note). POST-scoped, so the SCROLL/ATLAS/YARN/PULSE
// cards keep their plain dark %applet-box wash.
.applet-scroll {
background-color: rgba(var(--duoUser), 1);
> h2 {
// Match the New Post title strip exactly: three translucent
// 0,0,0/0.125 layers and NO opaque --priUser base, so the --duoUser
// felt shows THROUGH for the same green-tinted "partial mask". (On
// the billboard #id_applet_new_post lands here by accident — its
// opaque base is out-specified by %applet-box > h2's background-color;
// here we do it on purpose.) bg-color 0.125 + two gradients = 3 layers.
background-color: rgba(0, 0, 0, 0.125);
background-image:
linear-gradient(rgba(0, 0, 0, 0.125), rgba(0, 0, 0, 0.125)),
linear-gradient(rgba(0, 0, 0, 0.125), rgba(0, 0, 0, 0.125));
}
}
#id_post_table {
list-style: none;
margin: 0;
padding: 0 0.5rem 0 0;
padding: 0; // pills span the full card content width (= composer row)
flex: 1;
min-height: 0;
overflow-y: auto;
@@ -189,12 +211,23 @@ html.sea-open #id_aperture_fill {
flex-direction: column;
justify-content: flex-end; // bottom-anchor short threads
// Each line is styled to LOOK LIKE the "Enter a post line" composer
// input below it (mirrors .form-control, _base.scss): a --priUser fill +
// a 0.1rem --secUser border at the same border-radius, full width, an
// up/down margin and content-driven (dynamic) height — so the thread
// reads as a stack of input-style pills on the --duoUser felt.
.post-line {
display: grid;
grid-template-columns: minmax(4rem, auto) 1fr minmax(3rem, auto);
align-items: baseline;
gap: 0.5rem;
padding: 0.25rem 0;
width: 100%;
background-color: rgba(var(--priUser), 0.8);
border: 0.1rem solid rgba(var(--secUser), 0.5);
border-radius: calc((1rem + 1em) / 3); // == .form-control radius
margin: 0.35rem 0;
padding: 0.5rem 0.75rem;
box-shadow: 1px 1px 0.125rem 1px rgba(0, 0, 0, 0.6);
.post-line-author {
font-weight: bold;

View File

@@ -64,8 +64,12 @@
{# variant. #}
<input id="id_post_line_text" name="text" class="form-control"
placeholder="Enter a post line" autocomplete="off" required>
{# OK on an .applet-btn-panel so the green .btn-confirm reads #}
{# against the --duoUser felt — mirrors the New Post applet. #}
<div class="applet-btn-panel">
<button type="submit" id="id_post_line_btn" class="btn btn-confirm">OK</button>
</div>
</div>
<div id="id_post_line_feedback" class="invalid-feedback"></div>
</form>
</div>