End-of-session bundle 2026-05-26 covering ~10 distinct threads atop the A.7.5-polish-8 sky-wheel mini-portal commit (9cdd2cd). A.8 room.html sprint deferred per user — waiting on image scraping for RWS + future decks so the room can apply the image-mode pattern uniformly w.o. straddling text-mode fallback for unequippable Earthman Shabby Cardstock.
**(1) Game Kit + My Wallet applet realignment** — user spec "this isn't a place for tokens" / "only equippables should be there". Game Kit applet (/gameboard/, _applet-game-kit.html) drops the Free Token block — only PASS/BAND/CARTE/COIN trinkets + decks + dice remain. Free + Tithe tokens MOVED to the My Wallet applet on /dashboard/ (_applet-wallet.html rewrite). All trinkets COPIED into Wallet w. same .tt tooltip + DON/DOFF wiring so the user can equip from either surface. Stacked free/tithe icons (single icon per type) carry a .shop-badge ×N count (fa-coins for free, fa-piggy-bank for tithe — the latter standardized from outlier fa-hand-holding-dollar, now matching wallet / kit_bag / shop seed / FTs). Writs placeholder gets the same .token + .tt chrome ("Base currency unit ; Earned at the gate, spent in the shop"). 99+ cap on all badges. home_page view in apps/dashboard/views.py now passes pass/band/carte/coin + free/tithe tokens + counts + equipped_trinket_id. gameboard.js loaded on dashboard for the hover-portal tooltip system; #id_game_kit wrapper added (uses display: contents to stay transparent to the section-grid layout). Standalone game_kit.html page (_game_kit_sections.html) also reorganized — trinkets/tokens/decks each use bare .token icons w. centered flex row + 2rem gap, 1.5rem font-size to match gameboard sizing. id_game_kit outer wrapper data attrs (equipped-id, equipped-deck-id, in-use-deck-ids) feed buildMiniContent() for Equipped/Not Equipped/In-Use status.
**(2) My Sea label + shadow polish (my_sea.html Cross + applet)** — user spec "labels appear below and beneath the card, w. the card's shadow obscuring the very top of the label" per the GRAVITY/LEVITY .sea-stack-name pattern. .sea-pos-label repositioning: CROWN + COVER ABOVE slot (bottom: 100%; translate(-50%, -0.4rem)), LAY + CROSS BELOW slot (top: 100%; translate(-50%, 0.3rem)), LEAVE + LOOM increased breathing room (translate -0.4rem LEFT / 0.4rem RIGHT — was 0.1rem overlap). CROWN cell translateY(-0.5rem) UP + LAY cell translateY(0.5rem) DOWN for COVER/CROSS label breathing room. Filled-card downward shadow chain (1px 2px 0 black, 0 4px 0 black-faint, 2px 5px 5px black-blur) scoped to .my-sea-cross .sea-card-slot--filled only — empty dashed placeholders stay shadowless per user spec ("only the cards that replace [slots] should [have shadows]"). Four rotation-correction overrides for box-shadow rotating w. element transform: base (0deg), reversed (180deg sign-flip), cross (90deg matrix rotation → 2px -1px), cross+reversed (270deg → -2px 1px). Saved here for future reference since the matrix derivation is non-obvious: CSS rotate(θ) CW maps offset (a, b) → screen (a·cos θ − b·sin θ, a·sin θ + b·cos θ); solving for unrotated offsets that produce screen-down-right post-rotation gives the 4 chains. My Sea applet .my-sea-slot-label (z-index 0, margin-top 0.15rem) + .my-sea-slot--filled shadow + reversed-variant shadow inversion all mirror the page treatment.
**(3) DEL btn + FLIP btn state machine** — user spec: DEL un-disables as soon as ANY card drawn (was gated on hand_complete) ; FLIP btn .btn-disabled + text swap to × once hand complete. _setComplete(on) toggles FLIP btn class + label (parity w. DEL convention: × disabled / word active) ; new _setHasDrawn(on) helper extracted (was bundled in _setComplete). Wired into 4 transitions: (a) manual deposit _filled === 1, (b) initial page-load seed when _filled > 0, (c) AUTO DRAW path post-POST (CRITICAL FIX — was missing, only manual deposit synced DEL even though server already committed all cards on AUTO DRAW), (d) _resetHand spread-switch reset. Template DEL btn gates on saved_by_position (any draw); FLIP btn gates on hand_complete. Test test_partial_hand_del_btn_carries_btn_disabled inverted to test_partial_hand_del_btn_is_enabled per the new spec.
**(4) Sig-change MySeaDraw RESET (cooldown loophole closure)** — user-reported revenue-stream loophole 2026-05-26: switching sig used to re-open the FREE DRAW gate + forfeit any paid-draw credit, because apps/gameboard/views.py:266's `in_cooldown = active_draw is not None` keyed entirely off the MySeaDraw row's existence (NOT off User.last_free_draw_at, which is the cooldown TIMER but doesn't drive the in_cooldown decision). Initial draft DELETED the row on sig change — turned out too aggressive: lost both the cooldown anchor (created_at via the active_draw check) AND the paid-state fields (deposit_token_id, paid_through_at). FIX: save_sign on actual sig change `.update(hand=[], significator_id=new, significator_reversed=new)` — preserves cooldown + paid revenue, just resets the hand + sig snapshot. clear_sign left untouched (sig-cleared user can't draw anyway per my_sea_lock's no_significator guard; row sits dormant until re-pick routes through save_sign's reset). Guarded w. sig_changed so re-saving the same sig is a no-op. User.last_free_draw_at was always safe — User-level field, only ever set in my_sea_lock, never cleared (user confirmed the Brief shows 11:59pm consistently). Subtle architectural note for future: the in_cooldown decision being row-existence-based rather than timestamp-based is the load-bearing implicit dependency this loophole exposed; any refactor that delete()s the row needs to either flip in_cooldown to consult last_free_draw_at OR preserve the row as we did here.
**(5) Kit-bag DOFF async refresh** — user-reported 2026-05-26: deck disappears entirely from kit-bag on first DOFF; only manual page refresh restores the placeholder. Root cause: _syncKitBagDialog() in gameboard.js did card.querySelector('i') for the placeholder icon — worked for trinket/token cards (single FA <i>) but BROKE for image-equipped decks whose card-stack icon is <svg class="deck-stack-icon"> (no <i> to copy → empty placeholder div). DROP the client-side optimization, route both DOFF paths thru _refreshKitDialog() (symmetric w. DON). Single source of truth = server-rendered _kit_bag_panel.html's placeholder branch (re-renders _deck_stack_icon.html w.o. the deck arg for the empty-fill SVG).
**(6) Sky-wheel planet circle shadow** — user spec "tight 1px 1px black shadow at opacity 0.7 on planet circle groups in all sky locations". Base `filter: drop-shadow(1px 1px 0 rgba(0,0,0,0.7))` on .nw-planet-group so planet badges lift off the wheel rings on /dashboard/sky/ + My Sky applet + any future surface. Hover/active state chains shadow + glow ("drop-shadow ... ; drop-shadow(0 0 5px primary-lm)") since CSS filter REPLACES rather than APPENDS — shadow has to be re-stated on the hover rule to persist during interaction. Elements/signs/houses groups keep their glow-only hover (the request was planet-specific).
**(7) TarotCard suit_icon + Fiorentine additive numerals** — (a) suit_icon property pre-checks for major arcana trump 0 → fa-hat-cowboy-side (Fool/Nomad/Matto archetype) and trump 1 → fa-hat-wizard (Magician/Schizo/Bagatto archetype), pinned BEFORE the self.icon branch so even a deck seed supplying a different icon for these ranks normalizes to the convention. Earthman's seed already aligns; Minchiate (empty icon field) used to fall thru to fa-hand-dots. (b) _to_roman() adds _FIORENTINE_ADDITIVE_NUMERALS = {4:'IIII', 19:'XVIIII', 24:'XXIIII', 29:'XXVIIII', 34:'XXXIIII', 39:'XXXVIIII'} pre-check — locked-in 6-exception list per user-corrected spec (initial draft used universal additive form, user clarified "no, only these specific ones, e.g. trump 9 still prints IX + trump 14 still prints XIV per the actual Minchiate deck art"). +2 regression tests: additive overrides + non-overridden subtractive (9=IX, 14=XIV, 44=XLIV, 49=XLIX).
**(8) Gear menu NVM font fix** — _my_sea_gear.html's NVM btn changed from <a class="btn"> to <button onclick="location.href=..."> per [[feedback-btn-vs-anchor-font-family]] (anchor inherits body serif font; button stays sans-serif by browser default). Brief's NVM uses <button> + reads correctly — this matches it.
**(9) Image-mode slot transparency overrides** — 3 surfaces got `overflow: visible` (base overflow: hidden was clipping the contour-stroke filter chain) + transparent bg/border re-states for image-equipped Minchiate cards on (a) .my-sea-cross .sea-card-slot--filled + image variant, (b) .sig-stage-card.sea-sig-card.sig-stage-card--image base + levity-polarity nested override, (c) .sea-deck-stack--single .sea-stack-face:has(.sea-stack-face-img) (using :has() to key off the conditional back-img child). Followup to A.7.5-polish-* sprint — those surfaces' image-mode bg overrides didn't include overflow.
Tests: 1336/1336 IT+UT total green (was 1322 before the session). No FT runs per [[feedback-ft-run-discipline]]; visual verify ongoing by user across the session via Firefox reload.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
- _game-kit.scss #id_kit_btn landscape rule now uses `right: calc((var(--sidebar-w) - 3rem) / 2)` — same formula as gear-btn (_applets.scss) and bud-btn (_bud.scss). All three 3rem-wide circular btns now share the same horizontal-centre math against the fluid sidebar.
- Drops `@media (orientation: landscape) and (min-width: 1800px) { right: 2.5rem }` which was a leftover from the old doubled-8rem-sidebar regime; the rem clamp ceiling now caps the sidebar without per-breakpoint overrides.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- User.pronouns CharField w. choices=[pluralism (default), bawlmorese, misogyny, misandry, misanthropy] + pronoun_subj/obj/poss properties; PRONOUN_TABLE single source of truth in apps.lyric.models; mig 0002_user_pronouns
- drama.GameEvent.to_prose() drops module-level PRONOUN_* constants; SIG_READY/SIG_UNREADY/ROLE_SELECTED now resolve poss/subj from self.actor.pronouns at render time, so flipping a user's preference rewrites all their existing scroll prose; default actor → "their"
- SIG_READY prose strips a leading "The " from card_name so "the The Wanderer" reads "the Wanderer" and "the Engraven The Nomad" reads "the Engraven Nomad"; minor arcana ("Maid of Brands") untouched
- new applets/0005 seeds 'pronouns' applet (3x3, game-kit, default visible); _game_kit_sections.html grows a #id_gk_pronouns block w. 5 .gk-pronoun-card items labeled by ideology slug (italic) and tagged data-pronoun + data-trio
- card click → window.showGuard(card, "Set pronoun preference?<span class='guard-pronoun-trio'>{trio}</span>", commitCb); on OK fetches POST /dashboard/set-pronouns w. CSRF cookie + reloads so .active class moves and provenance prose re-renders; NVM dismisses
- dashboard.set_pronouns view (POST-only, login_required, 204/400/405) at /dashboard/set-pronouns; rejects choices not in PRONOUN_TABLE
- _game-kit.scss extends shared card rule to .gk-pronoun-card w. .active fill state + italic ideology label; #id_guard_portal .guard-pronoun-trio styled small/dim/centered under the question
- billscroll aperture: padding-right 0.75rem on #id_drama_scroll inside .applet-scroll so the timestamp column no longer sits beneath the scrollbar
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
- New _tooltips.scss: .token-tooltip/.tt base block extracted from _wallet-tokens.scss
- core.scss: import order …billboard → tooltips → game-kit → wallet-tokens
- _natus.scss: .tt-title--au/ag/…/pu (--six* dark, --pri* light) + .tt-title--el-* for element ring (--pri* dark, --ter* light) via body[class*="-light"] selector
- natus-wheel.js: element tooltip title switched from inline style to .tt-title--el-{key} CSS class; PLANET_ELEMENTS map drives .tt-title--{el} class on planet titles
- _game-kit.scss: kit bag .tt child font-size rules added (1rem title, 0.75rem desc/shoptalk/expiry)
- CLAUDE.md: SCSS import order updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New _card-deck.scss: sig select styles moved out of _room.scss + _game-kit.scss
- sig-select.js: 3 WS bug fixes — thumbs-up deferred to window.load (layout settled
before getBoundingClientRect), hover cursor cleared for all cards on reservation
(not just the reserved card), applyHover guards against already-reserved roles
- Own-role indicators: gamer now sees their own role-coloured card outline + thumbs-up
- Reservation glow: replaced blurry role+ninUser double-shadow with crisp 2px outline
- Gravity qualifier: Graven text set to --terUser (matches Leavened/--quiUser pattern)
- Role card SVGs refreshed; starter-role-Blank removed
- FTs + Jasmine specs extended for sig select WS behaviour
- setup_sig_session management command for multi-browser manual testing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
sizeSigModal() no longer uses tray bottomInset in landscape (was over-shrinking the
modal, pushing the stage off-screen); fixed 60px kit-bag-handle clearance instead.
Gear btn + kit btn shifted into the 4rem right sidebar strip (right: 0.5rem) and
nudged down a quarter-rem so they clear the last card in the 9×2 grid.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Split .gate-overlay into .gate-backdrop (z-100, blur) + .gate-overlay modal (z-120) so .table-position elements (z-110) render above backdrop but below modal
- New _table_positions.html partial: 6 .table-position divs with .fa-chair, role label, and .fa-ban/.fa-circle-check status icons; included unconditionally in room.html
- New epic:room view at /gameboard/room/<uuid>/; gatekeeper redirects there when table_status set; pick_roles redirects there
- role-select.js: adds .active glow to position on selectRole(); swaps .fa-ban→.fa-circle-check in placeCard onComplete; handleTurnChanged clears stale .active from all positions
- FTs: PositionIndicatorsTest (5 tests) + RoleSelectTest 8a/8b (glow + check state)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>