diff --git a/src/apps/epic/tests/integrated/test_views.py b/src/apps/epic/tests/integrated/test_views.py index d3db315..ae76c71 100644 --- a/src/apps/epic/tests/integrated/test_views.py +++ b/src/apps/epic/tests/integrated/test_views.py @@ -4137,12 +4137,23 @@ class PickSeaUnifiedFeltTest(TestCase): self.assertNotIn("sea-backdrop", content) self.assertNotIn("sea-modal-wrap", content) - def test_gaussian_spread_modal_with_preview_and_corner_nvm(self): + def test_options_on_felt_no_modal_no_nvm(self): + """The spread OPTIONS render directly on the felt (.sea-options-col) — + the combobox + OK + AUTO DRAW + DEL + the mini preview — mirroring Sky + Select's form-on-felt. The Gaussian modal + corner NVM are gone; OK + (.btn-confirm) shunts the options down to reveal the cross (user-spec + 2026-06-07).""" content = self.client.get(self.url).content.decode() - self.assertIn('id="id_sea_spread_modal"', content) - self.assertIn("my-sea-spread-modal__backdrop", content) - self.assertIn("sea-cross--preview", content) # mini preview - self.assertIn('id="id_sea_cancel"', content) # corner NVM + self.assertIn("sea-options-col", content) + self.assertIn("sea-cross-col", content) + self.assertIn('id="id_sea_confirm_spread"', content) # OK .btn-confirm + self.assertIn("sea-cross--preview", content) # mini preview kept + self.assertIn('id="id_sea_action_btn"', content) # AUTO DRAW + self.assertIn('id="id_sea_del"', content) # DEL + # The Gaussian modal + corner NVM are gone. + self.assertNotIn('id="id_sea_spread_modal"', content) + self.assertNotIn("my-sea-spread-modal__backdrop", content) + self.assertNotIn('id="id_sea_cancel"', content) def test_auto_draw_replaces_lock_hand(self): content = self.client.get(self.url).content.decode() diff --git a/src/apps/epic/views.py b/src/apps/epic/views.py index ac64cfb..0f20604 100644 --- a/src/apps/epic/views.py +++ b/src/apps/epic/views.py @@ -687,6 +687,11 @@ def _role_select_context(room, user, seat_param=None): ) # 6-card Celtic Cross is complete at 6 placed cards. ctx["hand_complete"] = len(_sea_hand) >= 6 + # Burger Sea sub-btn = the post-completion REOPEN affordance (active + # only once the spread is complete, like the Sky sub-btn after a save + # — NOT during drawing). So a reload of a complete sea renders it + # active; the live cascade activates it client-side otherwise. + ctx["sea_btn_active"] = ctx["hand_complete"] # Sea-stage FLIP card-back — sourced from the SEAT's contributed deck, # NOT request.user.equipped_deck (which `select_role` nulls out once # the deck is contributed to the room → the back-img silently never diff --git a/src/static_src/scss/_sky.scss b/src/static_src/scss/_sky.scss index 833883d..ac25f15 100644 --- a/src/static_src/scss/_sky.scss +++ b/src/static_src/scss/_sky.scss @@ -85,6 +85,8 @@ html.sea-open { inset: 0; z-index: 5; display: flex; + flex-direction: column; + overflow-y: auto; // the felt is the scroller (options ⇄ cross) background: rgba(var(--duoUser), 1); // Hidden until opened — pointer-events off so the hidden felt can't eat the // DRAW SEA btn click beneath it. @@ -97,6 +99,48 @@ html.sea-open .sea-page.sea-page--room { pointer-events: auto; } +// ── Sea felt sections — mirror Sky Select's form→wheel scroll-snap ──────────── +// #id_sea_overlay is a layout passthrough so the two sections become direct flex +// children of the scroller for scroll-snap (like `.sky-modal-body{display:contents}`). +.sea-page--room .sea-overlay-content { display: contents; } + +.sea-page--room .sea-options-col, +.sea-page--room .sea-cross-col { + flex: 1 0 auto; + min-height: 100%; + display: flex; + align-items: center; + justify-content: center; + position: relative; // pins the deck stacks to the cross section +} + +// The options form blends onto the --duoUser felt (transparent, content-sized) — +// "the modal contents on green felt", not the modal's purple --priUser card. +.sea-page--room .sea-options-col .sea-form-col { + background: transparent; + width: auto; + min-width: 14rem; +} + +// Pre-confirm: only the options show (the cross is hidden), filling the aperture +// (mirrors `body:not(.sky-saved) .sky-wheel-col{display:none}`). +.sea-page--room:not(.sea-spread-chosen) .sea-cross-col { display: none; } + +// OK → the aperture flips into scroll-snap: the cross takes page 1 (order:-1) + +// the options shunt to page 2. Mirrors the `body.sky-saved` block. +.sea-page--room.sea-spread-chosen { + scroll-snap-type: y mandatory; + + .sea-options-col, + .sea-cross-col { + scroll-snap-align: start; + scroll-snap-stop: always; + height: 100%; + flex: 0 0 auto; + } + .sea-cross-col { order: -1; } +} + // Hide the position strip while the sea felt is up (same as the sky felt) so the // felt reads as a clean homogeneous surface. html.sea-open .position-strip { diff --git a/src/templates/apps/gameboard/_partials/_sea_overlay.html b/src/templates/apps/gameboard/_partials/_sea_overlay.html index be08783..f409619 100644 --- a/src/templates/apps/gameboard/_partials/_sea_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sea_overlay.html @@ -1,158 +1,148 @@ {% load static %} {% comment %} -DRAW SEA — Sea Select felt + Gaussian spread modal, unified with my_sea.html -(2026-06-07). Replaces the legacy dark single-modal. TWO surfaces, mirroring -my_sea: - • Sea Select FELT (.sea-page--room) — a --duoUser fill of the hex pane; the - real Celtic-Cross spread deals here + the deck stacks. Opened by - #id_pick_sea_btn (html.sea-open); the room gear's NVM returns to the hex. - • Gaussian spread MODAL (#id_sea_spread_modal) — the .sea-select combobox - (the two Celtic Cross 6-card options ONLY, per user-spec 2026-06-07) + - AUTO DRAW + DEL + a miniaturized shape preview + a corner #id_sea_cancel - NVM (closes back to the felt). Opened via the burger #id_sea_btn. -Each draw persists onto the seat's Character.celtic_cross via epic:sea_save. +DRAW SEA — Sea Select felt (2026-06-07), mirroring Sky Select's form→wheel +scroll-snap. The felt starts with the spread OPTIONS (.sea-options-col, page 1): +the .sea-select combobox (the two Celtic Cross spreads only) + a mini shape +preview + OK + AUTO DRAW + DEL. Clicking OK confirms the spread → the options +shunt DOWN and the spread CROSS (.sea-cross-col, w. the Gravity/Levity deck +stacks) takes page 1 via scroll-snap (scroll down to find the options again). +NO modal, NO corner NVM. The burger #id_sea_btn is the post-completion REOPEN +affordance (active only once the spread is complete, like the sky btn) — NOT +active during drawing. Each draw persists onto the seat's Character.celtic_cross +via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs. {% endcomment %} -
-
+
- {# ── Felt cross — the REAL deal target (.my-sea-cross). Sig pins core; the #} - {# six CC positions render w. labels + saved-hand pre-fill. The default #} - {# spread is the polarity-matched Celtic Cross (or the saved one). #} -
-
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="crown" saved=saved_by_position.crown crossing=False %} -
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="leave" saved=saved_by_position.leave crossing=False %} -
-
- {# Center significator — supply the card-FACE image when the sig's #} - {# deck has one (mirrors my_sea); else fall through to the corner- #} - {# rank + suit-icon text thumbnail (the tray sig stays text-only). #} - {# my_tray_sig's deck_variant is the card's OWN deck (the Sig #} - {# Select pick comes from the Role Select contributed deck via #} - {# _room_deck_variant), so this is the right image source. #} -
- {% if my_tray_sig %} - {% if my_tray_sig.deck_variant.has_card_images %} - {{ my_tray_sig.name }} - {% else %} - {{ my_tray_sig.corner_rank }} - {% if my_tray_sig.suit_icon %}{% endif %} - {% endif %} - {% endif %} -
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="cover" saved=saved_by_position.cover crossing=False %} -
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="cross" saved=saved_by_position.cross crossing=True %} -
-
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="loom" saved=saved_by_position.loom crossing=False %} -
-
- - {% include "apps/gameboard/_partials/_my_sea_slot.html" with position="lay" saved=saved_by_position.lay crossing=False %} -
-
-
- - {# ── Deck stacks — pinned bottom-right of the felt, so FLIP stays usable #} - {# while the spread modal is closed. ALWAYS two stacks (Gravity + Levity), #} - {# unlike my_sea / Sig Select: in the room's Sea Select phase the gamer may #} - {# draw from EITHER populated half (sea_deck returns both), even a CARTE #} - {# user whose monodeck is presented across the two polarity stacks #} - {# (user-spec 2026-06-07). So the polarization-conditional shared partial #} - {# is intentionally NOT used here. #} -
-
- DECKS -
-
- -
- Gravity -
-
-
- -
- Levity -
-
-
- - {# ── Gaussian spread modal — opens on the burger #id_sea_btn. #} -