Commit Graph

16 Commits

Author SHA1 Message Date
Disco DeDisco
3242873625 btn-primary label renames + stage-card polarity color refinements — two interleaved threads from one session, committing together since both touch sig + sea stage cards ; LABEL RENAMES: PICK SIGS → SCAN SIGS (room.html #id_pick_sigs_btn), PICK SKY → CAST SKY (room.html #id_pick_sky_btn × 2), PICK SEA → DRAW SEA (room.html #id_pick_sea_btn), TAKE SIG → SAVE SIG (sig-select.js _takeSigBtn.textContent × 2 callsites + section comment) — Element IDs (id_pick_sky_btn etc.), URL names (epic:pick_sigs, epic:pick_sky), and Python state enums (TableStatus.PICK_SKY, PICK_SEA, SIG_SELECT) intentionally retained as stable identifiers; the renamed text is purely the .btn-primary user-facing label ; FT + IT mentions of the old labels swept in test_game_room_select_{sig,sky,sea,role}.py, test_billboard.py, setup_sea_session.py mgmt cmd, apps/epic/{views,utils,models,tasks,tests/integrated/test_views}.py, SigSelectSpec.js, sky_overlay/sea_overlay/dashboard/sky.html, _card-deck.scss, _sky.scss — all docstring/comment references updated for cascade-grep cleanliness ; STAGE-CARD COLOR + CLASS REFINEMENTS (earlier in session): sig-stage card text colour split per polarity — gravity gets --terUser on .fan-card-name + .fan-card-reversal-{name,qualifier} + .sig-qualifier-{above,below}, levity gets --quiUser on the same five slots; all selectors prefixed w. .sig-stage-card to match the 0,4,0 specificity of the default .sig-stage .sig-stage-card .fan-card-face .sig-qualifier-* rule (without the prefix the polarity overrides lose the cascade — .sig-qualifier-below was visibly stuck on the default --quiUser) ; .stat-face-label gets polarity-inverse colours — gravity stat-block bg is --secUser (opposite of card's --priUser) so the label takes --quiUser to stay legible; levity is the symmetric flip (label = --terUser on --priUser stat-block bg) ; levity card title/qualifier drop-shadow swapped from rgba(0,0,0,…) → rgba(255,255,255,…) — dark drop reads as harsh smudge against the inverted-frame levity --secUser bg; applied to both sig-overlay[data-polarity="levity"] stage card AND sea-stage--levity via $_sea-title-shadow-levity (former shared $_sea-title-shadow split into per-polarity {levity,gravity} variants) ; reversal-face class/content alignment so each .fan-card-reversal-* class always carries its semantic content — DOM order per arcana type controls visual layout after the 180° SPIN (DOM-second appears visually on top): Major → title in .fan-card-reversal-name @ DOM-second (visually top after spin), qualifier in .fan-card-reversal-qualifier @ DOM-first; Non-major → title in .fan-card-reversal-name @ DOM-first (visually bottom after spin), qualifier in .fan-card-reversal-qualifier @ DOM-second (preserves the original "qualifier word reads first after spin" layout for Middle/Minor arcana — e.g. "Relieving / Eight of Crowns" not "Eight of Crowns / Relieving") ; _tarot_fan.html renders per-arcana DOM order directly (Django template branches handle both layouts); sig + sea overlays render a fixed two-<p> skeleton (one DOM order) so stage-card.js's populator dynamically rewrites the two <p>s' className per arcana — Major/override branch flips DOM-second to .fan-card-reversal-name + content, DOM-first to .fan-card-reversal-qualifier; non-major branch keeps DOM-first as .fan-card-reversal-name + title, DOM-second as .fan-card-reversal-qualifier + reversalQualifier-or-polarity-fallback ; SigSelectSpec.js + SeaDealSpec.js fixtures + Major reversed-face assertion updated for the new semantic — TDD
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 00:25:10 -04:00
Disco DeDisco
3932b17256 aperture architecture: lift the page-locking foundation (html/body/.container overflow:hidden + flex-column + min-height:0; .row flex-shrink:0) from 5 per-page SCSS files into _base.scss — was opt-in per page via body.page-billboard / page-dashboard / page-gameboard / page-sky / page-wallet etc., with 5 near-identical html:has(body.page-X) { overflow: hidden } + body.page-X { … } blocks duplicating the same rules; any page that forgot to set page_class in its view context (e.g. epic.tarot_deck — never set) rendered without the aperture, letting applet borders + titles clip past the fixed navbar/footer sidebars at narrower viewports; foundation now universal, page-specific overrides stay scoped — gameboard keeps .container { overflow: clip } (Firefox seat-tooltip scroll-anchoring quirk) + billboard/dashboard/gameboard keep .row { margin-bottom: -1rem } (h2-row tightening); page_class context vars + body class hooks preserved (FTs at test_bud_btn.py:370 / :379 still assert on them); regression gate: 60 layout-sensitive FTs (billboard, my_buds, bud_btn, applet_my_posts, dashboard, wallet, gameboard, layout_and_styling, jasmine) + 43 room FTs (gatekeeper_bud_btn, room_gatekeeper, room_sky_select, sharing) all green
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:16:12 -04:00
Disco DeDisco
df99cad984 mobile h2 + sky wheel landscape fit: per-letter flex spread (justify-content: space-between via base.html JS letter-splitter) replaces text-justify: inter-character — iOS Safari + Firefox silently fall back to inter-word for Latin text, leaving letters clustered at the slot start; flex layout works everywhere; viewport-fluid font clamp(1.3rem, 5vw, 2rem) portrait + clamp(1.2rem, 4.4vh, 2.75rem) landscape so glyphs scale w. viewport instead of a fixed-rem ceiling that overflowed the 45/55 slot at the rem-clamp floor; portrait <500px gets padding-inline 0.4em→0.6em on the word-spans so H-B don't run together at the cramped font-size; .sky-page post-save scroll-snap sections pinned to height: 100% (was: min-height: 100%) + .sky-svg max-height: 100% so the wheel fits exactly one aperture on landscape mobile (was: 480px max blew past ~350px aperture, leaving an intermediate scroll position)
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 14:01:16 -04:00
Disco DeDisco
d58fd1db15 small changes to .sky-field styling 2026-05-08 15:41:24 -04:00
Disco DeDisco
846f9ff461 PICK SKY DEL: server purge of seat Character + race guards stop the btn from re-injecting; readonly opacity bump (0.6 → 0.85) — TDD
Two related Sky Select bugs the old DEL flow couldn't address. (1) DEL btn lingered after a clear because an in-flight schedulePreview's .then() could resolve AFTER the OK callback ran, calling _ensureDelBtn() against a freshly-cleared wheel-col. (2) Sky data rehydrated on refresh because clicking SAVE SKY confirms a Character row on the seat — the DEL handler only purged localStorage & in-memory state, leaving the durable Character row to drive subsequent renders.

Server: new epic.sky_delete(room_id) view (POST → JsonResponse {deleted:True}) deletes every Character on the requesting gamer's seat where retired_at is null — drafts (confirmed_at NULL) and confirmed rows alike. 405 on GET, 403 for outsiders, never touches User.sky_chart_data (Dashsky/My Sky applet's DEL owns that side).

JS (_sky_overlay.html): DEL OK callback now (a) bumps a _fetchSeq counter so any in-flight schedulePreview .then()/.catch() short-circuits when its captured seq != current — kills the re-injection race; (b) clearTimeout-s _chartDebounce + _placeDebounce so a typed-just-before-DEL keystroke can't fire schedulePreview after the clear; (c) POSTs to DELETE_URL (overlay.dataset.deleteUrl wired via {% url 'epic:sky_delete' room.id %}) so the seat's Character row is dropped server-side; (d) clears LS + DOM state as before.

SCSS: .sky-field input[readonly] opacity 0.6 → 0.85, & dropped the redundant .sky-coords > div input { opacity:0.6 } that was previously winning the cascade by virtue of being declared later. The browser's default ::placeholder is ~0.54, so 0.85 × 0.54 ≈ 0.46 — close to the birth-place placeholder's ~0.54 effective opacity per the user's "appreciably higher tho not opacity 1" target. Values land at 0.85 (clearly readable but still de-emphasized vs. the editable place input).

Tests: 4 new ITs in PickSkyRenderingTest cover (a) POST clears confirmed Character, returns JSON {deleted:True}; (b) 405 on GET; (c) 403 for non-seat-owner; (d) User.sky_chart_data untouched by in-room DEL. PickSkyDelTest FT picks up an extra assertion: id_sky_delete_btn must be absent from DOM after OK (the bug-1 regression guard). 55-test sky suite green.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 15:39:07 -04:00
Disco DeDisco
097a5dd437 my-sky applet DEL btn: shift left by half the applet's padding asymmetry so it re-aligns w. the SVG center
The applet section uses padding 0.75rem 0.75rem 0.75rem 2.5rem — the 2.5rem left gutter holds the rotated h2 — so the SVG's geometric center lands 0.875rem right of the applet's padding-box center. Absolute positioning on the DEL btn references the padding box center, which put the btn 14px left of the wheel's actual center. Compensating w. left:calc(50% + 0.875rem) on #id_applet_sky_delete_btn re-aligns the btn (verified 0px dx/dy in the live browser). The other two DEL anchors (Dashsky #id_sky_delete_form & PICK SKY #id_sky_delete_btn) live in symmetric .sky-wheel-col containers so the base 50%/50% rule still works for them.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 14:44:54 -04:00
Disco DeDisco
e9bceaab62 sky wheel: ubiquitous DEL btn — applet & PICK SKY parity w. Dashsky; PICK SKY clears client-only state (no User-model touch) — TDD
My Sky applet (.../dashboard/_partials/_applet-my-sky.html): adds <button id="id_applet_sky_delete_btn" class="btn btn-danger"> at the wheel center, gated on user.sky_chart_data. Click → window.showGuard("Forget sky?") → on OK, fetch POSTs sky_delete (clears every sky_* field on User), removes the 'sky-form:dashboard:sky' localStorage entry that would otherwise rehydrate the post-reload form via _restoreForm(), then reloads — applet's form-render branch is server-template-gated on chart_data so the page comes back form-only.

PICK SKY in-room overlay (.../gameboard/_partials/_sky_overlay.html): adds <button id="id_sky_delete_btn"> at the wheel center. The wheel here is purely a live preview — sky_save fires only on SAVE SKY click w. action='confirm', so there's no draft Character to delete & we do NOT touch the Character/User model. The DEL handler clears the SVG, resets form fields (including lat/lon/tz/tzHint), nulls _lastChartData, disables the SAVE SKY btn, & purges the LS_KEY entry that would otherwise rehydrate on next overlay open / page refresh. Mirrors the user's spec ("shouldn't be targeting the user model anyway, only the character/seat model" — and there's currently no character/seat draft in the PICK SKY flow).

Both handlers defer the window.showGuard readiness check to click-time rather than gating the listener bind itself: window.showGuard is assigned by a base.html script that lives BELOW the content block, so an `if (window.showGuard)` gate at script-execute time would skip the bind entirely (we hit this writing the applet handler — manifested as portal class never receiving 'active' on click).

SCSS: extends the existing #id_sky_delete_form absolute-center rule onto the two new btn IDs (#id_sky_delete_btn, #id_applet_sky_delete_btn). #id_applet_my_sky picks up position:relative as the absolute anchor for the applet btn.

FTs: MySkyAppletDelTest (applet → DEL → guard → OK → reload, asserts User cleared + LS purged + form re-renders) & PickSkyDelTest (overlay → fill form → wheel paints → DEL → guard → OK, asserts SVG empty + form blank + LS purged). Both red before the wiring, green after; full sky suite (46 tests) green.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 14:34:41 -04:00
Disco DeDisco
283b417341 sky.html: tame iOS Firefox date/time native widgets w. appearance:none + max-width; mirror small-landscape btn-primary scaling onto portrait & narrow form-col gap on both
iOS Firefox renders <input type="date|time"> with a native widget whose intrinsic content width ignores min-width:0 alone, so the date/time pills bled past .sky-form-main while text-input siblings fit fine. Adding appearance:none + -webkit-appearance:none on the two input types drops the native chrome so width/padding/border are honored uniformly across pills (the picker still opens on tap); max-width:100% on the .sky-field input baseline is belt-&-suspenders for any other widget that ignores min-width:0.

The .btn-primary shrink-to-2.75rem rule that lived under (orientation:landscape) and (max-width:1100px) now also fires on (orientation:portrait), so SAVE SKY scales down on phone portrait aperture too. Same media envelope narrows .sky-page .sky-form-col gap from 1rem → 0.4rem so SAVE SKY tucks closer to #id_sky_status & the form fits short-aspect phones without clipping the btn against the footer.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 14:04:15 -04:00
Disco DeDisco
c8d7b055d7 sky.html: clip horizontal overflow on iOS Firefox — .sky-page overflow-x:hidden + min-width:0 on .sky-field input
iOS Firefox renders <input type="date"> & <input type="time"> with a native widget whose minimum content width can exceed .sky-form-main on narrow phones, spilling past the form column & triggering page-level horizontal scroll. Two defensive layers: (1) min-width:0 on .sky-field input lets the native widget shrink below its intrinsic content width; (2) overflow-x:hidden on .sky-page clips anything that still slips past — the aperture is the snap scroll container so this only affects the column-stack direction we don't want anyway. body.page-sky already has overflow:hidden but iOS Firefox doesn't always honor it for native form controls.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:18:30 -04:00
Disco DeDisco
9ff437012a sky.html: DEL btn at wheel center; async SAVE SKY transitions into saved state without reload; pre-save hides wheel-col so form+SAVE SKY stay centered — TDD
DEL btn (.btn-danger, "Forget sky?" data-confirm wired to the global #id_guard_portal) sits absolutely centered inside .sky-wheel-col; OK submits a POST to the new sky_delete view, which clears every sky_* field on the User model & redirects back to /dashboard/sky/.

The sky.html aperture is now uniform across saved/unsaved: form-col is always flex-column align-center justify-center so the fields + SAVE SKY pair sits visually centered. body.sky-saved adds *only* the snap-binary scroll layer (scroll-snap-type:y, modal-body display:contents, cols min-height:100% scroll-snap-align:start, wheel-col aspect-ratio cap released, form-col flex:0 0 auto so the snap basis wins) — the column-stacking is no longer gated.

Async save: SAVE SKY's success branch now calls _activateSavedState(), which adds body.sky-saved, draws the wheel from _lastChartData, pins overlay.scrollTop to the form section's offsetTop, then runs the existing _scrollApertureToTop ease-out so the wheel reveals from above instead of replacing the form with a hard cut. The wheel preview that previously redrew during typing is now gated on _savedSky — pre-first-save typing fetches the chart data (so SAVE SKY enables) but does not render the wheel, mirroring the My Sky applet's "no wheel until saved" UX. The in-room PICK SKY overlay (_sky_overlay.html) still previews live, deliberately untouched.

Pre-save the wheel-col is hidden via `body:not(.sky-saved) .sky-page .sky-wheel-col { display: none }`, so the empty SVG can't shunt the form below the fold (& the DEL btn rides the same selector since it lives inside .sky-wheel-col).

Tests: SkyDeleteTest IT class (5: clears fields, redirects, 405 on GET, login required, preserves unrelated user fields). MySkyDeleteFlowTest FT class (3: DEL btn visibility gated on sky data, NVM dismisses w. data intact, OK clears + reverts body class). MySkyAsyncSaveTest FT (1: fresh user → SAVE SKY → body picks up sky-saved, wheel SVG populates, DEL btn becomes visible — all without a page reload). All 13 sky FTs + sky ITs green; existing MySkyApertureSnapScrollTest & MySkyTimezoneRefreshTest still pass.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:07:56 -04:00
Disco DeDisco
bbd1b22bb0 sky.html post-save: reset (max-width:600px) form-main height cap & btn align-self so flex-column flip lands the SAVE SKY beneath the fields
Two carried-over rules from the @media (max-width:600px) block — written for the in-room PICK SKY modal where form-col is flex-row — collide with body.sky-saved's flex-column flip on .sky-page: (1) .sky-form-col > #id_sky_confirm{align-self:flex-end}, which means "bottom" under flex-row but "right" under flex-column, was pushing the btn to the right edge instead of centering it; (2) .sky-form-main{max-height:40vh; overflow-y:auto} clamped form-main into a tiny inner-scroll well. body.sky-saved now resets both — align-self:auto on the btn (inherits the col's align-items:center) & max-height:none + overflow-y:visible on form-main (the aperture handles scroll, not form-main).

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:30:01 -04:00
Disco DeDisco
05c9f9c079 sky.html post-save: stack SAVE SKY beneath form fields & vertically center the pair, parity w. wheel
.sky-page .sky-form-col defaults to flex-row align-end (form-main left, btn bottom-right). Under body.sky-saved that pinned the SAVE SKY btn to the corner under the snap layout — fix is flex-direction:column + align-items:center + justify-content:center, gap:1rem so the btn sits a clear rem below the form-main. .sky-page .sky-form-main capped at max-width:22rem so the input pills don't stretch the full landscape-mobile aperture width.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:27:47 -04:00
Disco DeDisco
319b787109 sky.html: snap-binary aperture scroll (wheel ↔ form, full aperture each); SAVE SKY animates scrollTop back to 0 — TDD
post-save the .sky-page aperture flips into scroll-snap-y-mandatory mode: wheel-col & form-col each fill the aperture & carry scroll-snap-align:start, so vertical scroll toggles between them rather than free-flowing through both. Modal-body uses display:contents so the cols become direct flex children of .sky-page (where min-height:100% resolves against the explicit aperture height); wheel-col's aspect-ratio/max-height caps are released under body.sky-saved so the section actually fills the aperture instead of clipping at 480px. SAVE SKY's success branch calls _scrollApertureToTop(), a 280ms RAF loop w. ease-out cubic so the user lands back on the wheel after confirming from the form section. New FT class MySkyApertureSnapScrollTest covers (T1) snap-type:y mandatory + scroll-snap-align:start on both cols, (T2) scrollTop returns to 0 after SAVE SKY click; both red before the SCSS+JS, green after. Snap behavior is gated on body.sky-saved (set by sky_view based on user.sky_chart_data) so the pre-save form-only flow is untouched.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:24:11 -04:00
Disco DeDisco
3beedc3f0a sky form: flip label margins so each label hugs its own input below; zero geo-btn vertical margin so birth place doesn't drift
.sky-field gap goes 0.25rem → 0 so label sits flush above its own input. Field-to-field spacing moves into a `& + & { margin-top: 0.4rem }` rule; small explanation text gets margin-top:0.2rem so it stays separated from the input it annotates. .sky-coords inner column gap zeroed for parity. .sky-place-wrap zeroes the geo button's inherited 4px top/bottom margin from .btn — without that, the wrap was 40px tall (vs 33px input) and align-items:center pushed the place input 4px below its label, leaving birth place as the lone field with a visible label-input gap.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:00:03 -04:00
Disco DeDisco
9e68cfd8e4 sky form inputs: form-control look (gold border, pill, page-bg fill, focus glow); login email label matches sky-field label style
.sky-field input now mirrors .form-control's priUser fill / secUser border & text / pill border-radius / terUser focus glow — same look as the login email input. Readonly inputs (lat/lon) keep opacity:0.6. .input-group label (the "enter email for login" line above the email input) now adopts .sky-field label styling: 0.6rem uppercase, 0.1em letter-spacing, quaUser at 0.8 — so the login form's label/input pair reads as the same component as the sky-field rows.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 11:53:05 -04:00
Disco DeDisco
cc2a3f3526 rename natus → sky across the codebase — natal chart abstraction is now sky throughout, since chart inputs aren't birthday-gated
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed
Mechanical rename: 5 files (sky-wheel.js, _sky.scss, _sky_overlay.html, SkyWheelSpec.js x2), 24 in-place edits across templates/views/urls/SCSS/JS/tests/CLAUDE.md. URL names epic:natus_save → epic:sky_save (epic namespaced, no clash w. dashboard:sky_save), JS module NatusWheel → SkyWheel, DOM ids id_natus_* → id_sky_*, BEM classes natus-* → sky-*, dashboard sky_natus_data/sky_natus_preview collapsed to sky_data/sky_preview_data. No DB migration needed (User.sky_chart_data + GameEvent.SKY_SAVED already used sky-prefix). 778 ITs + Jasmine green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:36:15 -04:00