The table becomes a full oval racetrack with a center deck and pot plaque, perimeter seats as compact pills with stack-first readouts that flash on change, betting actions mounted on the felt near the viewer, your own cards dealt onto the bottom rail at community-card size, directional popups, and gated start and waiting-room polish.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Snapshot diffs surface fold, check, bet, call, raise, all-in, and pot-win text over each seat, leavers announce centrally, and new hands open with a small-blind then big-blind sequence before the first real turn. Popups fire exactly once per event with reduced-motion fallbacks.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Web audio synth with zero audio assets: deal whooshes, chip clacks, turn chimes, showdown and win stingers, plus a lazy 92bpm jazz loop. Transitions drive playback from pure snapshot mappers with staggered delays for the blind sequence, a header mute and volume toggle persists, and everything no-ops safely without audio support.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Faces render white with dark ink by default, the previous dark theme cards remain one toggle away, and the classic deck draws the svg assets from public/images/assets/playing-cards. The choice persists per browser.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Leavers now flip a left flag on the very next snapshot, the felt announces who left, and a game left with a single seated player resolves at once with a bell notification instead of waiting out the hand timer.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Also scopes the MCP plugin to explicit per-collection eligibility (mcpCollections).
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- The compose modal gains an optional channel select (text and
announcement channels), preselected with the configured default
- /announce now posts only to the announce channel by default: the ops
fallback is gone, so an unconfigured announce channel errors instead
of silently posting to ops
- Roll call was already ops-only and is unchanged
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- /announce with no message opens a modal: optional title field plus a
4000-char paragraph body for multi-line markdown
- Target channel rides in the modal customId; staff is re-checked on
submit and the post goes out as the same amber Announcement embed
- Inline message flow unchanged; modal submits route under ptf-announce:
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Widget wrappers use flex-1 with a min-w-0 chain so cards stay at their
grid-cell width instead of shrinking to content or overflowing it
- ItemContent gains min-w-0 so nowrap text ellipsizes inside the card
(notifications, campaigns, tickets) rather than clipping at the viewport
- Stretched Service Summary and Mission Briefing top-pack their content;
Mission Briefing header flips between Next Mission and Last Mission
- Drag-and-drop widget arrangement (main two-column zone + sidebar) with
per-widget span resize, persisted to Users.preferences.dashboard.layout
via saveDashboardLayout (migration included)
- New personal widgets: Wallet, Open Negotiations, My Tickets (View all),
Recent Notifications (per-row mark as read)
- Widgets that are empty or not visible to the viewer are omitted so they
never render as empty drag targets
- Registers both pending migrations and regenerates payload types/schema
- Missions.codeName is now optional (still unique when set); migration included
- Campaign and side-op dialogs accept an optional cover image (uploadUgcImage)
- Reminder toasts, evaluation aggregates, calendar, cards and mission headers
handle a null code name
- Mission read filter no longer hides drafts by status; visibility follows
ownershipAndStatus.visibility only
- briefing is now self-paced (player clicks Begin recall; no memo countdown)
- recall quiz has a hard server-validated time band per tier (45/60/75s limits, minimum plausible human time, 2.5s grace); scripted instant or over-limit submissions are rejected
- briefing is rendered on canvas: no selectable text in the DOM, copy/cut/context-menu/ctrl-a-c-x-s-p blocked; screenshots remain possible but burn quiz time
- ?seed=<n> URL param pins a deterministic scenario (no server meaning; used by the e2e spec to know the grid)
- e2e spec updated for the new flow and asserts no grid text leaks into the DOM
Deposits/withdrawals of stock (economy-mutating) are now superuser-only, while moving items around (transfer/place/collect) stays open to logistics-qualified users; seed roles updated to match. ManageStorageDialog reworked alongside its toolbar/button/view wrappers, and the structure page wires up the new permission split.
Logistics entries are collapsed into collapsible groups, Personnel moves from its own sidebar section into Logistics, and an Event Log entry is added to Intelligence.
New /events page rendering the full game event ledger (system + narrative events) with type/target/source/date filtering, backed by a shared shadcn table component.
Adds a 'Mark as Ready' control on the mission detail page (owner or missions:update gated) plus the markSideOpReady server action. Status-gated to Concept/Planning/Scheduled; emits a mission:ready event. Stops the daily ready-reminders and lets missionEmbeds post the roll-call.
Five days before a player-created side op starts, if it is not yet Ready, the creator gets one in-app notification per day (via mission-tick) plus one Discord DM per day (new bot service). Per-server-local-day dedupe via hidden readyReminderWebSentAt/readyReminderDmSentAt markers. The ready-reminder type is excluded from the notification bridge to avoid double-DMing. Markers are nulled on clone.
Side ops now credit their creator: mission cards get a 'Hosted by X' meta entry and the mission detail page gets a Host chip. Display name preferred over username; only shown for side ops with a populated createdBy.
Add provisioning a personal bank account, toggling background texture and callsign display, and copying the page link; the layout now passes user preferences and personal-account state so the palette can hide or handle them.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Cover transfers, projects, Friday Ops calendar, wiki, NPC personnel, awards, voiceover, and the training minigames.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Normalize every submission to mono 96 kbps MP3 so takes play everywhere regardless of the recording codec; falls back to storing the original file when ffmpeg is unavailable or fails.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>